package com.ruoyi.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysTaskPlan;
import com.ruoyi.common.core.domain.entity.SysTaskPlanDetail;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.pojo.AddTaskPlanReq;
import com.ruoyi.common.pojo.GetUserTaskPlanReq;
import com.ruoyi.common.pojo.QueryTaskPlanListReq;
import com.ruoyi.common.pojo.UpdateTaskPlanReq;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.quartz.domain.SysJob;
import com.ruoyi.quartz.util.CronUtil;
import com.ruoyi.quartz.util.ScheduleUtils;
import com.ruoyi.system.mapper.SysTaskPlanDetailMapper;
import com.ruoyi.system.mapper.SysTaskPlanMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.SysTaskPlanService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author syj
 * @description 针对表【sys_task_plan】的数据库操作Service实现
 * @createDate 2022-09-28 16:58:40
 */
@Service
public class SysTaskPlanServiceImpl extends ServiceImpl<SysTaskPlanMapper, SysTaskPlan>
        implements SysTaskPlanService {

    @Autowired
    private Scheduler scheduler;

    @Qualifier("threadPoolTaskExecutor")
    @Autowired
    ThreadPoolTaskExecutor executor;

    @Resource
    SysUserMapper sysUserMapper;

    @Resource
    SysTaskPlanMapper sysTaskPlanMapper;

    @Resource
    SysTaskPlanDetailMapper sysTaskPlanDetailMapper;

    @Override
    public AjaxResult queryTaskPlan(QueryTaskPlanListReq param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<SysTaskPlan> sysTaskPlans = new ArrayList<>();
        List<SysTaskPlanDetail> sysTaskPlanDetails = null;
        //if (ObjectUtil.isEmpty(param.getUserId())) {
        sysTaskPlans = sysTaskPlanMapper.selectList(Wrappers.<SysTaskPlan>lambdaQuery()
                .eq(Objects.nonNull(param.getType()), SysTaskPlan::getType, param.getType())
                //.eq(Objects.nonNull(param.getFinish()), SysTaskPlan::getFinish, param.getFinish())
                .eq(Objects.nonNull(param.getTaskType()), SysTaskPlan::getTaskType, param.getTaskType())
                .eq(SysTaskPlan::getState, 1)
                .eq(Objects.nonNull(param.getFlowpath()), SysTaskPlan::getFlowpath, param.getFlowpath())
                .ge(StringUtils.isNotBlank(param.getStartTime()), SysTaskPlan::getStartTime, DateUtils.parseDate(param.getStartTime()))
                .le(StringUtils.isNotBlank(param.getEndTime()), SysTaskPlan::getEndTime, DateUtils.parseDate(param.getEndTime()))
                .orderByDesc(SysTaskPlan::getCreateTime)
        );

//        } else {
//            sysTaskPlanDetails = sysTaskPlanDetailMapper.selectList(Wrappers.<SysTaskPlanDetail>lambdaQuery()
//                    .eq(SysTaskPlanDetail::getUserId, param.getUserId())
//                    .eq(SysTaskPlanDetail::getState, 1)
//                    .eq(Objects.nonNull(param.getFinish()), SysTaskPlanDetail::getFinish, param.getFinish())
//            );
//            List<Long> userPlanList = sysTaskPlanDetails.stream().map(SysTaskPlanDetail::getPlanId).collect(Collectors.toList());
//            if (CollUtil.isNotEmpty(userPlanList)) {
//                sysTaskPlans = sysTaskPlanMapper.selectList(Wrappers.<SysTaskPlan>lambdaQuery()
//                        .in(SysTaskPlan::getId, userPlanList)
//                        .eq(Objects.nonNull(param.getType()), SysTaskPlan::getType, param.getType())
//                       // .eq(Objects.nonNull(param.getFinish()), SysTaskPlan::getFinish, param.getFinish())
//                        .eq(Objects.nonNull(param.getTaskType()), SysTaskPlan::getTaskType, param.getTaskType())
//                        .eq(SysTaskPlan::getState, 1)
//                        .eq(SysTaskPlan::getFlowpath, 2)
//                        .ge(StringUtils.isNotBlank(param.getStartTime()), SysTaskPlan::getStartTime, DateUtils.parseDate(param.getStartTime()))
//                        .le(StringUtils.isNotBlank(param.getEndTime()), SysTaskPlan::getEndTime, DateUtils.parseDate(param.getEndTime()))
//                        .orderByDesc(SysTaskPlan::getCreateTime)
//                );
//            }
//        }

        SysUser paramUser = null;
//        if (ObjectUtil.isEmpty(param.getUserId())) {
//            paramUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, param.getUserId()));
//        }

        for (SysTaskPlan sysTaskPlan : sysTaskPlans) {
            SysUser creatorUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getCreatorId()));
            sysTaskPlan.setCreatorName(creatorUser.getNickName());

            if (ObjectUtil.isNotNull(sysTaskPlan.getPublishUserId())) {
                SysUser runUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getPublishUserId()));
                sysTaskPlan.setPublishUserName(runUser.getNickName());
            }

            if (ObjectUtil.isNotNull(sysTaskPlan.getStopUserId())) {
                SysUser closeUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getStopUserId()));
                sysTaskPlan.setStopUserName(closeUser.getNickName());
            }

            //if (ObjectUtil.isEmpty(param.getUserId())) {
            sysTaskPlanDetails = sysTaskPlanDetailMapper.selectList(Wrappers.<SysTaskPlanDetail>lambdaQuery()
                    .eq(SysTaskPlanDetail::getPlanId, sysTaskPlan.getId())
                    .eq(SysTaskPlanDetail::getState, 1)
            );
            for (SysTaskPlanDetail sysTaskPlanDetail : sysTaskPlanDetails) {
                SysUser takeUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getCreatorId()));
                if (ObjectUtil.isNotNull(takeUser)) {
                    sysTaskPlanDetail.setUserName(takeUser.getNickName());
                }
            }
            sysTaskPlan.setUserList(sysTaskPlanDetails);
//           }  else {
//                List<SysTaskPlanDetail> sysTaskPlanDetailList = sysTaskPlanDetails.stream().filter(v -> StrUtil.equals(String.valueOf(v.getPlanId()), String.valueOf(sysTaskPlan.getId()))).collect(Collectors.toList());
//                for (SysTaskPlanDetail sysTaskPlanDetail : sysTaskPlanDetailList) {
//                    if (ObjectUtil.isNotNull(paramUser)) {
//                        sysTaskPlanDetail.setUserName(paramUser.getNickName());
//                    }
//                }
//                sysTaskPlan.setUserList(sysTaskPlanDetailList);
//            }
        }

        PageInfo<SysTaskPlan> pageInfo = new PageInfo<SysTaskPlan>(sysTaskPlans);
        return AjaxResult.success(pageInfo);
    }

    @Override
    public AjaxResult getTaskPlan(Long id) {
        SysTaskPlan taskPlan = sysTaskPlanMapper.selectById(id);
        SysUser creatorUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, taskPlan.getCreatorId()));
        taskPlan.setCreatorName(creatorUser.getNickName());

        if (ObjectUtil.isNotNull(taskPlan.getPublishUserId())) {
            SysUser runUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, taskPlan.getPublishUserId()));
            taskPlan.setPublishUserName(runUser.getNickName());
        }

        if (ObjectUtil.isNotNull(taskPlan.getStopUserId())) {
            SysUser closeUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, taskPlan.getStopUserId()));
            taskPlan.setStopUserName(closeUser.getNickName());
        }
        List<SysTaskPlanDetail> sysTaskPlanDetails = sysTaskPlanDetailMapper.selectList(Wrappers.<SysTaskPlanDetail>lambdaQuery()
                .eq(SysTaskPlanDetail::getPlanId, taskPlan.getId())
                .eq(SysTaskPlanDetail::getState, 1)
        );

        for (SysTaskPlanDetail sysTaskPlanDetail : sysTaskPlanDetails) {
            SysUser takeUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, taskPlan.getCreatorId()));
            if (ObjectUtil.isNotNull(takeUser)) {
                sysTaskPlanDetail.setUserName(takeUser.getNickName());
            }
        }
        taskPlan.setUserList(sysTaskPlanDetails);
        return AjaxResult.success(taskPlan);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
    public AjaxResult addTaskPlan(AddTaskPlanReq param) {
        List<Long> userList = param.getUserList();
        DateTime nowDate = DateUtil.date();
        long time = nowDate.getTime();
        SysTaskPlan sysTaskPlan = SysTaskPlan.builder()
                .creatorId(SecurityUtils.getUserId())
                .taskName(param.getTaskName())
                .remarks(param.getRemarks())
                .cycleId(time)
                .finish(0)
                .createTime(nowDate)
                .startTime(param.getStartTime())
                .endTime(param.getEndTime())
                .state(1)
                .type(1)
                .taskType(2)
                .flowpath(1)
                .build();
        sysTaskPlanMapper.insert(sysTaskPlan);
        SysTaskPlanDetail sysTaskPlanDetail = null;
        for (Long userId : userList) {
            sysTaskPlanDetail = new SysTaskPlanDetail();
            sysTaskPlanDetail.setPlanId(sysTaskPlan.getId());
            sysTaskPlanDetail.setUserId(userId);
            sysTaskPlanDetail.setFinish(0);
            sysTaskPlanDetail.setState(1);
            sysTaskPlanDetailMapper.insert(sysTaskPlanDetail);
        }
        executor.execute(() -> {
            if (nowDate.isBefore(sysTaskPlan.getEndTime())) {
                SysJob job = new SysJob();
                job.setJobId(sysTaskPlan.getId());
                job.setJobName(sysTaskPlan.getTaskName());
                job.setStatus("0");
                job.setMisfirePolicy("1");
                job.setJobGroup("SYSTEM");
                job.setInvokeTarget("ryTask.stopTaskPlan(" + sysTaskPlan.getId() + "L)");
                job.setConcurrent("0");
                job.setCronExpression(CronUtil.getCron(sysTaskPlan.getEndTime()));
                try {
                    ScheduleUtils.createScheduleJob(scheduler, job);
                } catch (Exception e) {
                    log.error("定时结束任务异常", e);
                }
            } else {
                SysTaskPlan taskPlan = SysTaskPlan.builder()
                        .flowpath(3)
                        .build();
                sysTaskPlanMapper.update(taskPlan, Wrappers.<SysTaskPlan>lambdaUpdate()
                        .eq(SysTaskPlan::getId, sysTaskPlan.getId())
                        .eq(SysTaskPlan::getFlowpath, 2)
                        .eq(SysTaskPlan::getState, 1)
                );
            }
        });

        return AjaxResult.success(true);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
    public AjaxResult editTaskPlan(UpdateTaskPlanReq param) {
        List<Long> userList = param.getUserList();
        DateTime nowDate = DateUtil.date();
        SysTaskPlan sysTaskPlan = SysTaskPlan.builder()
                .taskName(param.getTaskName())
                .remarks(param.getRemarks())
                .updateTime(nowDate)
                .reviseId(SecurityUtils.getUserId())
                .startTime(param.getStartTime())
                .endTime(param.getEndTime())
                .build();
        int update = sysTaskPlanMapper.update(sysTaskPlan, Wrappers.<SysTaskPlan>lambdaUpdate()
                .eq(SysTaskPlan::getId, param.getId())
                .eq(SysTaskPlan::getState, 1)
                .eq(SysTaskPlan::getFlowpath, 1)
        );
        if (update > 0) {
            sysTaskPlanDetailMapper.delete(Wrappers.<SysTaskPlanDetail>lambdaUpdate().eq(SysTaskPlanDetail::getPlanId, param.getId()));
            SysTaskPlanDetail sysTaskPlanDetail = null;
            for (Long userId : userList) {
                sysTaskPlanDetail = new SysTaskPlanDetail();
                sysTaskPlanDetail.setPlanId(param.getId());
                sysTaskPlanDetail.setUserId(userId);
                sysTaskPlanDetail.setFinish(0);
                sysTaskPlanDetail.setState(1);
                sysTaskPlanDetailMapper.insert(sysTaskPlanDetail);
            }
        }

        executor.execute(() -> {
            if (nowDate.isBefore(sysTaskPlan.getEndTime())) {
                SysJob job = new SysJob();
                job.setJobId(sysTaskPlan.getId());
                job.setJobName(sysTaskPlan.getTaskName());
                job.setStatus("0");
                job.setMisfirePolicy("1");
                job.setJobGroup("SYSTEM");
                job.setInvokeTarget("ryTask.stopTaskPlan(" + sysTaskPlan.getId() + "L)");
                job.setConcurrent("0");
                job.setCronExpression(CronUtil.getCron(sysTaskPlan.getEndTime()));
                try {
                    JobKey jobKey = ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup());
                    if (scheduler.checkExists(jobKey)) {
                        // 防止创建时存在数据问题 先移除，然后在执行创建操作
                        scheduler.deleteJob(jobKey);
                    }
                    ScheduleUtils.createScheduleJob(scheduler, job);
                } catch (Exception e) {
                    log.error("定时结束任务异常", e);
                }
            } else {
                SysTaskPlan taskPlan = SysTaskPlan.builder()
                        .flowpath(3)
                        .build();
                sysTaskPlanMapper.update(taskPlan, Wrappers.<SysTaskPlan>lambdaUpdate()
                        .eq(SysTaskPlan::getId, sysTaskPlan.getId())
                        .eq(SysTaskPlan::getFlowpath, 2)
                        .eq(SysTaskPlan::getState, 1)
                );
            }
        });
        return AjaxResult.success(SqlHelper.retBool(update));
    }

    @Override
    public AjaxResult publishTaskPlan(Long id) {
        SysTaskPlan sysTaskPlan = SysTaskPlan.builder()
                .publishUserId(SecurityUtils.getUserId())
                .publishTime(DateUtil.date())
                .flowpath(2)
                .build();
        int update = sysTaskPlanMapper.update(sysTaskPlan, Wrappers.<SysTaskPlan>lambdaUpdate()
                .eq(SysTaskPlan::getFinish, 0)
                .eq(SysTaskPlan::getState, 1)
                .eq(SysTaskPlan::getFlowpath, 1)
                .eq(SysTaskPlan::getType, 1)
                .eq(SysTaskPlan::getTaskType, 2)
                .eq(SysTaskPlan::getId, id)
        );
        return AjaxResult.success(SqlHelper.retBool(update));
    }

    @Override
    public AjaxResult stopTaskPlan(Long id) {
        SysTaskPlan sysTaskPlan = SysTaskPlan.builder()
                .stopUserId(SecurityUtils.getUserId())
                .stopTime(DateUtil.date())
                .flowpath(4)
                .build();
        int update = sysTaskPlanMapper.update(sysTaskPlan, Wrappers.<SysTaskPlan>lambdaUpdate()
                .eq(SysTaskPlan::getId, id)
        );
        return AjaxResult.success(SqlHelper.retBool(update));
    }

    @Override
    public AjaxResult deleteTaskPlan(Long id) {
        SysTaskPlan sysTaskPlan = SysTaskPlan.builder()
                .state(0)
                .build();
        int update = sysTaskPlanMapper.update(sysTaskPlan, Wrappers.<SysTaskPlan>lambdaUpdate()
                .eq(SysTaskPlan::getId, id)
                .eq(SysTaskPlan::getFlowpath, 1)
        );
        return AjaxResult.success(SqlHelper.retBool(update));
    }

    @Override
    public AjaxResult getUserTaskPlan(GetUserTaskPlanReq param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<SysTaskPlan> sysTaskPlans = new ArrayList<>();
        List<SysTaskPlanDetail> sysTaskPlanDetails = sysTaskPlanDetailMapper.selectList(Wrappers.<SysTaskPlanDetail>lambdaQuery()
                .eq(SysTaskPlanDetail::getUserId, SecurityUtils.getUserId())
                .eq(SysTaskPlanDetail::getState, 1)
                .eq(Objects.nonNull(param.getFinish()), SysTaskPlanDetail::getFinish, param.getFinish())
                .orderByDesc(SysTaskPlanDetail::getId)
        );
        Set<Long> userPlanList = sysTaskPlanDetails.stream().map(SysTaskPlanDetail::getPlanId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(userPlanList)) {
            sysTaskPlans = sysTaskPlanMapper.selectList(Wrappers.<SysTaskPlan>lambdaQuery()
                    .in(SysTaskPlan::getId, userPlanList)
                    .eq(Objects.nonNull(param.getType()), SysTaskPlan::getType, param.getType())
                    .eq(Objects.nonNull(param.getFinish()), SysTaskPlan::getFinish, param.getFinish())
                    .eq(Objects.nonNull(param.getTaskType()), SysTaskPlan::getTaskType, param.getTaskType())
                    .eq(SysTaskPlan::getState, 1)
                    .eq(Objects.nonNull(param.getFlowpath()), SysTaskPlan::getFlowpath, param.getFlowpath())
                    .ge(StringUtils.isNotBlank(param.getStartTime()), SysTaskPlan::getStartTime, DateUtils.parseDate(param.getStartTime()))
                    .le(StringUtils.isNotBlank(param.getEndTime()), SysTaskPlan::getEndTime, DateUtils.parseDate(param.getEndTime()))
                    .orderByDesc(SysTaskPlan::getCreateTime)
            );

            for (SysTaskPlan sysTaskPlan : sysTaskPlans) {
                SysUser creatorUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getCreatorId()));
                sysTaskPlan.setCreatorName(creatorUser.getNickName());

                if (ObjectUtil.isNotNull(sysTaskPlan.getPublishUserId())) {
                    SysUser runUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getPublishUserId()));
                    sysTaskPlan.setPublishUserName(runUser.getNickName());
                }

                if (ObjectUtil.isNotNull(sysTaskPlan.getStopUserId())) {
                    SysUser closeUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getStopUserId()));
                    sysTaskPlan.setStopUserName(closeUser.getNickName());
                }

                sysTaskPlanDetails = sysTaskPlanDetailMapper.selectList(Wrappers.<SysTaskPlanDetail>lambdaQuery()
                        .eq(SysTaskPlanDetail::getPlanId, sysTaskPlan.getId())
                        .eq(SysTaskPlanDetail::getState, 1)
                );
                for (SysTaskPlanDetail sysTaskPlanDetail : sysTaskPlanDetails) {
                    SysUser takeUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserId, sysTaskPlan.getCreatorId()));
                    if (ObjectUtil.isNotNull(takeUser)) {
                        sysTaskPlanDetail.setUserName(takeUser.getNickName());
                    }
                }
                sysTaskPlan.setUserList(sysTaskPlanDetails);
            }
        }
        PageInfo<SysTaskPlan> pageInfo = new PageInfo<SysTaskPlan>(sysTaskPlans);
        return AjaxResult.success(pageInfo);
    }

}




